using QFramework;
using QGameFramework.Models;
using QGameFramework.Tools;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using QFramework.Game;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.U2D;

namespace QGameFramework.QResources
{
    public class ResourcesComponent : BaseComponent
    {
        #region 全局变量

        /// <summary>
        /// 加载AB包工具
        /// </summary>
        public ResLoader m_ResLoader;

        /// <summary>
        /// 工具
        /// </summary>
        private Tool m_Tools;

        /// <summary>
        /// 游戏设置
        /// </summary>
        private IGameConfig GameConfig;

        /// <summary>
        /// 资源字典
        /// </summary>
        private static Dictionary<string, ResourceInfo> m_ResourceDict = new Dictionary<string, ResourceInfo>();

        #endregion

        #region 重写函数

        /// <summary>
        /// 初始化
        /// </summary>
        public override void OnInit()
        {
            GameConfig = this.GetModel<IGameConfig>();
            m_Tools = this.GetUtility<Tool>();
            m_ResLoader = ResLoader.Allocate();

            //每60秒清理一次资源
            InvokeRepeating("UnloadAll", GameConfig.CleanTime, GameConfig.CleanTime);
        }

        /// <summary>
        /// 反初始化
        /// </summary>
        public override void DeInit()
        {
            base.DeInit();
            GameConfig = null;
            m_Tools = null;
            m_ResourceDict.Clear();
            m_ResLoader.Recycle2Cache();
            Resources.UnloadUnusedAssets();
        }

        #endregion

        #region 字典相关操作

        /// <summary>
        /// 添加到资源字典
        /// </summary>
        /// <param name="path"></param>
        /// <param name="resourceInfo"></param>
        private void Add2ResDict(string path, ResourceInfo resourceInfo)
        {
            //有空间直接添加
            if (GameConfig.MaxResourcesCount > 0 && m_ResourceDict.Count <= GameConfig.MaxResourcesCount)
            {
                m_ResourceDict.Add(path, resourceInfo);
            }
            //空间不足 删除应用为空，长时间未使用的资源
            else if (m_ResourceDict.Count > GameConfig.MaxResourcesCount)
            {
                foreach (var res in m_ResourceDict.Values)
                {
                    if (res.m_ReferenceCount == 0 && m_Tools.DiffSeconds(res.m_LastAccessTime, DateTime.Now) > 60)
                    {
                        RemoveFromResDict(res.m_Path);
                        UnityEngine.Resources.UnloadUnusedAssets();
                        QGFC.Instance.Reference.m_ReferencePool.Release(res);
                        //break会导致每次只清除一个资源
                        break;
                    }
                }

                //有空间直接添加
                m_ResourceDict.Add(path, resourceInfo);
            }
        }


        /// <summary>
        /// 通过路径移除资源
        /// </summary>
        /// <param name="path">资源路径</param>
        private void RemoveFromResDict(string path)
        {
            if (m_ResourceDict.ContainsKey(path))
            {
                QGFC.Instance.Reference.m_ReferencePool.Release(m_ResourceDict[path]);
                m_ResourceDict.Remove(path);
                Resources.UnloadUnusedAssets();
            }
        }

        /// <summary>
        /// 通过资源类移除资源
        /// </summary>
        /// <param name="info">资源信息</param>
        private void RemoveFromResDict(ResourceInfo info)
        {
            if (m_ResourceDict.ContainsKey(info.m_Path))
            {
                LogKit.I($"清理资源{info.m_Path}");
                m_ResourceDict.Remove(info.m_Path);
                QGFC.Instance.Reference.m_ReferencePool.Release(info);
                Resources.UnloadUnusedAssets();
            }
        }

        #endregion

        #region 资源加载

        /// <summary>
        /// 加载资源
        /// </summary>
        /// <param name="path">资源路径</param>
        public void LoadAssets(string path, UnityAction<byte[], ResourceInfo> CallBack = null)
        {
            //文件存在
            if (File.Exists(path))
            {
                if (m_ResourceDict.ContainsKey(path))
                {
                    LogKit.I("从缓存加载");
                    m_ResourceDict[path].m_ReferenceCount = 1;
                    m_ResourceDict[path].m_LastAccessTime = DateTime.Now;
                    CallBack?.Invoke(m_ResourceDict[path].m_Resources, m_ResourceDict[path]);
                }
                else
                {
                    //开启携程加载资源
                    LogKit.I("从硬盘加载");
                    StartCoroutine(IE_LoadAssets(path, CallBack));
                }
            }
            else
            {
                LogKit.E("资源路径不存在");
            }
        }

        /// <summary>
        /// 加载资源携程
        /// </summary>
        /// <param name="path">资源路径（视频，音效，图片，文字）</param>
        /// <param name="Callback">回调事件</param>
        /// <returns></returns>
        IEnumerator IE_LoadAssets(string path, UnityAction<byte[], ResourceInfo> CallBack = null)
        {
            using (UnityWebRequest webRequest = UnityWebRequest.Get(path))
            {
                yield return webRequest.SendWebRequest();

                if (webRequest.result != UnityWebRequest.Result.Success)
                {
                    LogKit.E("加载资源异常！！！");
                }
                else
                {
                    //加载资源完成，即将执行回调函数
                    byte[] bytes = webRequest.downloadHandler.data;

                    var info = QGFC.Instance.Reference.m_ReferencePool
                        .Acquire<ResourceInfo>();

                    info.m_Path = path;
                    info.m_ReferenceCount = 1;
                    info.m_Resources = bytes;
                    info.m_LastAccessTime = DateTime.Now;

                    Add2ResDict(info.m_Path, info);

                    CallBack?.Invoke(bytes, info);
                    //同 Callback(bytes,info)
                }
            }
        }

        public void UnloadAssets(string path)
        {
            LogKit.I($"需要减少引用的资源路径{path}");
            if (m_ResourceDict.ContainsKey(path))
            {
                m_ResourceDict[path].m_ReferenceCount--;
            }
        }

        public void UnLoadAssetsImediately(string path)
        {
            if (m_ResourceDict.ContainsKey(path))
            {
                m_ResourceDict.Remove(path);
                Resources.UnloadUnusedAssets();
            }
        }

        /// <summary>
        /// 卸载所有资源
        /// </summary>
        public void UnloadAll()
        {
            if (m_ResourceDict.Count > 0 && m_ResourceDict != null)
            {
                var infos = new List<ResourceInfo>(m_ResourceDict.Values);
                for (int i = 0; i < infos.Count; i++)
                {
                    if (infos[i].m_ReferenceCount < 1 &&
                        m_Tools.DiffSeconds(infos[i].m_LastAccessTime, DateTime.Now) > GameConfig.CleanTime)
                    {
                        RemoveFromResDict(infos[i]);
                    }
                }
            }
        }


        /// <summary>
        /// 加载图集
        /// </summary>
        /// <param name="name">图集名</param>
        /// <param name="Callback">回调函数</param>
        public void LoadSpriteAtlas(string name, UnityAction<SpriteAtlas> Callback = null)
        {
            m_ResLoader.Add2Load<SpriteAtlas>("name");
            m_ResLoader.LoadAsync(() =>
            {
                LogKit.I("Load SpriteAtlas Success");
                Callback?.Invoke(m_ResLoader.LoadSync<SpriteAtlas>(name));
            });
        }

        #endregion

        #region 生命周期函数

        #endregion
    }
}